﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using HtmlAgilityPack;
using System.IO;
using System.Net;
using AAA.Base.Util;

namespace AAA.Web
{
    public class HtmlFileParser
    {
        public const int DO_NOT_APPEND_COL = 0;
        public const int APPEND_COL_RIGHT = 1;
        public const int APPEND_COL_LEFT = 2;
        
        
        private Dictionary<string, string> _dicField;
        private Dictionary<string, string> _dicFieldId;
        private Dictionary<string, string> _dicFieldValue;

        private Encoding _encoding = Encoding.UTF8;
        
        public Encoding Encoding
        {
            get { return _encoding; }
            set { _encoding = value; }
        }

        private Encoding _convertEncoding;

        public Encoding ConvertEncoding
        {
            get { return _convertEncoding; }
            set { _convertEncoding = value; }
        }

        private HtmlDocument _rootDocument;

        public HtmlDocument RootDocument
        {
            get { return _rootDocument; }
            set { _rootDocument = value; }
        }

        private string _strSourceFile;

        public string SourceFile
        {
            get { return _strSourceFile; }
            set { _strSourceFile = value; }
        }


        public HtmlFileParser()
        {
            _dicField = new Dictionary<string, string>();
            _dicFieldId = new Dictionary<string, string>();
            _dicFieldValue = new Dictionary<string, string>();
        }

        public void AddParseField(string strField, string strXPath)
        {
            if (_dicField.ContainsKey(strField))
                _dicField[strField] = strXPath;
            else
                _dicField.Add(strField, strXPath);
        }

        public void AddParseFieldId(string strField, string strFieldId)
        {
            if (_dicFieldId.ContainsKey(strField))
                _dicFieldId[strField] = strFieldId;
            else
                _dicFieldId.Add(strField, strFieldId);
        }

        public List<string> GetFieldList()
        {
            List<string> lstField = new List<string>();

            try
            {
                foreach (string strKey in _dicField.Keys)
                    lstField.Add(strKey);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message + "," + ex.StackTrace);
            }

            return lstField;
        }

        public string GetFieldValue(string strField)
        {
            return _dicFieldValue.ContainsKey(strField)
                    ? _dicFieldValue[strField]
                    : null;
        }

        public void ParsePages(string strImportPath, string strExportPath, string strXPath)
        {
            try
            {

            }
            catch (Exception ex)
            {
            }
        }

        public string ParseElementById(string strId)
        {
            if (RootDocument == null)
                RootDocument = LoadDocument(SourceFile);

            return ParseElementById(RootDocument, strId);
        }

        public string ParseElementById(HtmlDocument doc, string strId)
        {
            string strValue = null;
            HtmlNode node;
            string strSavedId = null;
            try
            {
                if ((node = doc.DocumentNode.SelectSingleNode(string.Format("//*[@id='{0}']", strId))) != null)
                {
                    strValue = node.InnerText;
                    if ((ConvertEncoding != Encoding) && (ConvertEncoding != null))
                        strValue = StringHelper.CharSetConvert(strValue, Encoding, ConvertEncoding);

                    strSavedId = _dicFieldId.ContainsKey(strId) ? _dicFieldId[strId] : strId;

                    if (_dicFieldValue.ContainsKey(strSavedId))
                        _dicFieldValue[strSavedId] = strValue;
                    else
                        _dicFieldValue.Add(strSavedId, strValue);
                }
                    
            }
            catch (Exception ex)
            {
            }

            return strValue;
        }

        public List<List<string>> ParseElement(HtmlNode rootNode)
        {
            HtmlNodeCollection colCollection;
            List<List<string>> lstResult = new List<List<string>>();
            List<string> lstRow;

            foreach (HtmlNode row in rootNode.ChildNodes)
            {
                colCollection = row.ChildNodes;
                lstRow = new List<string>();
                foreach (HtmlNode col in colCollection)
                {
                    lstRow.Add(col.InnerText);
                }
                lstResult.Add(lstRow);
            }
            return lstResult;
        }        

        public void ParseTable(string strSourceFile, string strTargetFile, string strXPath, string strDelimater)
        {
            ParseTable(strSourceFile, strTargetFile, strXPath, strDelimater, 0, -1);
        }

        public void ParseTable(string strSourceFile, string strTargetFile, string strXPath, string strDelimater, int iColCount)
        {
            ParseTable(strSourceFile, strTargetFile, strXPath, strDelimater, 0, iColCount);
        }

        public void ParseTable(string strSourceFile, string strTargetFile, string strXPath, string strDelimater, int iSkipRow, int iColCount)
        {
            ParseTable(strSourceFile, strTargetFile, strXPath, strDelimater, iSkipRow, new int[] {iColCount}, DO_NOT_APPEND_COL);
        }

        private HtmlDocument LoadDocument(string strSourceFile)
        {
            FileStream fileStream = null;
            MemoryStream ms = null;
            HtmlDocument doc = null;
            try
            {
                fileStream = new FileStream(strSourceFile, FileMode.Open, FileAccess.Read);
                
                byte[] bData = new byte[fileStream.Length];

                fileStream.Read(bData, 0, bData.Length);

                //將原始檔轉為MemoryStream, 才能讀取中文內容
                ms = new MemoryStream(bData);
                //                HtmlDocument docDataTable = new HtmlDocument();
                doc = new HtmlDocument();
                doc.Load(ms, Encoding);
            }
            catch (Exception ex)
            {

            }
            finally
            {
                if (fileStream != null)
                    fileStream.Close();
            }
            return doc;
        }

        public void ParseTable(string strTargetFile, string strXPath, string strDelimater, int iSkipRow, int[] iColCounts, int iAppendSide)
        {
            ParseTable(SourceFile, strTargetFile, strXPath, strDelimater, iSkipRow, iColCounts, iAppendSide);
        }

        public void ParseTable(string strSourceFile, string strTargetFile, string strXPath, string strDelimater, int iSkipRow, int[] iColCounts, int iAppendSide)
        {
            StreamWriter sw = null;
            FileStream fileStream = null;
            string strLine;
            List<string> lstRow;
            try
            {
                _dicFieldValue = new Dictionary<string,string>();
                sw = new StreamWriter(strTargetFile);
                List<List<string>> nodeCollection;
                //WebClient webClient = new WebClient();
                //fileStream = new FileStream(strSourceFile, FileMode.Open);
                //byte[] bData = new byte[fileStream.Length];
                bool isSkip;
                int iMaxCol;

                //fileStream.Read(bData, 0, bData.Length);

                //將原始檔轉為MemoryStream, 才能讀取中文內容
                //MemoryStream ms = new MemoryStream(bData);
                //HtmlDocument doc = new HtmlDocument();
                HtmlDocument docDataTable = new HtmlDocument();
                //doc.Load(ms, Encoding);

                HtmlDocument doc = (strSourceFile == null ? RootDocument : LoadDocument(strSourceFile));

                string strInnerHTML = doc.DocumentNode.SelectSingleNode(strXPath).InnerHtml;
                docDataTable.LoadHtml(doc.DocumentNode.SelectSingleNode(strXPath).InnerHtml);

                nodeCollection = ParseElement(docDataTable.DocumentNode);

                iMaxCol = 0;
                foreach (int iColCount in iColCounts)
                    iMaxCol = iMaxCol < iColCount ? iColCount : iMaxCol;

                for(int i = iSkipRow; i < nodeCollection.Count; i++)
                {
                    lstRow = nodeCollection[i];
                    strLine = "";

                    isSkip = true;
                    for(int j = 0; j < iColCounts.Length; j++)
                        if ((lstRow.Count == iColCounts[j]))
                        {
                            isSkip = false;
                            break;
                        }

                    if(isSkip)
                        continue;

                    if((lstRow.Count < iMaxCol) && (iAppendSide == APPEND_COL_LEFT))
                    {
                        for(int j = 0; j < iMaxCol - lstRow.Count; j++)
                            strLine += strDelimater;
                    }

                    foreach (string strValue in lstRow)
                    {
                        strLine += strDelimater + strValue.Replace(strDelimater, "").Replace("\r", "").Replace("\n", "");
                    }

                   if((lstRow.Count < iMaxCol) && (iAppendSide == APPEND_COL_RIGHT))
                    {
                        for(int j = 0; j < iMaxCol - lstRow.Count; j++)
                            strLine += strDelimater;
                    }
                    sw.WriteLine(strLine.Substring(strDelimater.Length));
                }
                sw.Close();
                
                if (_dicField.Count > 0)
                {
                    sw = new StreamWriter(strTargetFile + ".fields");

                    foreach (string strField in _dicField.Keys)
                    {
                        sw.Write(strField + "=" + doc.DocumentNode.SelectSingleNode(_dicField[strField]).InnerHtml);
                        _dicFieldValue.Add(strField, doc.DocumentNode.SelectSingleNode(_dicField[strField]).InnerHtml);
                    }

                    sw.Close();
                }

            }
            catch (Exception ex)
            {

            }
            finally
            {
                if (sw != null)
                    sw.Close();

                if (fileStream != null)
                    fileStream.Close();
            }
        }
    }
}
